package com.wuliang.generate.common.core.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.context.annotation.Lazy;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author WuLiang
 */
@Lazy
@Slf4j
public class FileUtils {

    public static final String CACHE_FILE_DIRECTORY = "/home/wuliang/exportCache/";

    /**
     * 字段对应释义
     *
     * @return 字段释义列表
     */
    public static Map<String, String> createFinanceResultLabel() {
        Map<String, String> keyLabel = new LinkedHashMap<>();
        return keyLabel;
    }

    /**
     * 根据列表生成表格
     *
     * @param excelContent 列表
     */
    public static void createExcelFile(Map<String, Object> excelContent, Map<String, String> labelList,
                                       String shopName) {
        // 创建一个工作簿
        Workbook workbook = new XSSFWorkbook();
        // 遍历数据键值对，有多少键就创建多少个sheet
        for (String sheetNameOfEN : excelContent.keySet()) {
            // 在工作簿中创建一个sheet，并以对应的释义命名，在追加一个字段名，以便于后续调用
            Sheet sheet = workbook.createSheet(labelList.get(sheetNameOfEN) + "(" + sheetNameOfEN + ")");
            List<Map<String, Object>> sheetContent = (List<Map<String, Object>>) excelContent.get(sheetNameOfEN);
            // 创建表头
            Row header = sheet.createRow(0);
            // 如果对应的表格内容为空，则不进行后续导出工作
            if (sheetContent.isEmpty()) {
                continue;
            }
            // 提起出一个样例，以制作表头
            List<String> excelHeader = sheetContent.get(0).keySet().stream().collect(Collectors.toList());
            // 遍历表头字段，以获取对应释义
            for (String keyFullName : excelHeader) {
                // 如果说字段名称中不包含 _ 则表示此字段不参与导出工作，仅用于数据格式化的逻辑
                if (!keyFullName.contains("_")) {
                    continue;
                }
                // 获取字段名称 _ 后的数字以用于表示在表头中的下标文职
                int headIndex = Integer.parseInt(keyFullName.substring(keyFullName.lastIndexOf("_") + 1));
                // 截取字段名称
                String headKey = keyFullName.substring(0, keyFullName.lastIndexOf("_"));
                // 如果当前字段在释义列表中存在，则获取对应释义，并以 (字段名称) 结尾 以便于后续操作
                if (labelList.containsKey(headKey)) {
                    Cell cell = header.createCell(headIndex);
                    // 例如  项目名称(itemName)
                    cell.setCellValue(labelList.get(headKey) + "(" + keyFullName + ")");
                }
            }
            // 遍历对应的数据内容
            for (int i = 0; i < sheetContent.size(); i++) {
                // 获取当前行的数据
                Map<String, Object> rowContent = sheetContent.get(i);
                // 创建下一行
                Row nextRow = sheet.createRow(i + 1);
                // 获取表头的单元格
                Iterator<Cell> cellIterator = header.cellIterator();
                // 遍历表头的单元格
                while (cellIterator.hasNext()) {
                    // 获取当前遍历的表头单元格
                    Cell heardCell = cellIterator.next();
                    // 截取表头上标注的键名
                    String keyName = heardCell.getStringCellValue()
                                              .substring(heardCell.getStringCellValue().indexOf("(") + 1,
                                                         heardCell.getStringCellValue().indexOf(")"));
                    // 截取表头上的标注的单元格下标
                    int headIndex = Integer.parseInt(keyName.substring(keyName.lastIndexOf("_") + 1));
                    // 根据上述下标创建数据单元格
                    Cell nextCell = nextRow.createCell(headIndex);
                    // 如果当前遍历的数据中包含这个键，则将数据写进单元格中
                    if (rowContent.containsKey(keyName)) {
                        nextCell.setCellValue(rowContent.get(keyName) == null? "" : rowContent.get(keyName).toString());
                    }
                }
            }
            // 清除表头多余内容
            clearHeader(sheet);
        }
        // 声明文件输出流， finally 别忘关流
        FileOutputStream fileOutputStream = null;
        try {
            // 将导出的文件内容输出到指定文件中，并以店铺名称命名文件
            fileOutputStream = new FileOutputStream(CACHE_FILE_DIRECTORY + "统计[" + shopName + "].xlsx");
            workbook.write(fileOutputStream);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                    workbook.close();
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }
            }
        }
    }

    /**
     * 格式化表头
     *
     * @param sheet sheet页
     */
    private static void clearHeader(Sheet sheet) {
        // 获取表头
        Row row = sheet.getRow(0);
        // 遍历单元格
        Iterator<Cell> cellIterator = row.cellIterator();
        int i = 0;
        while (cellIterator.hasNext()) {
            Cell cell = cellIterator.next();
            // 重写单元格内释义
            String headName = cell.getStringCellValue().substring(0, cell.getStringCellValue().indexOf("("));
            cell.setCellValue(headName);
            sheet.autoSizeColumn(i++);
        }
    }

}
